package com.nulldev.util.uri.yt.broken.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import com.nulldev.util.java.JVMUtil;

public class SubscriptionList implements Subscription {
    private List<Subscription> subscriptions;
    private volatile boolean unsubscribed;
    
    public SubscriptionList() {
    }
    
    public SubscriptionList(final Subscription... subscriptions) {
        this.subscriptions = new LinkedList<Subscription>(Arrays.<Subscription>asList(subscriptions));
    }
    
    public SubscriptionList(final Subscription s) {
        (this.subscriptions = new LinkedList<Subscription>()).add(s);
    }
    
    @Override
    public boolean isUnsubscribed() {
        return this.unsubscribed;
    }
    
    public void add(final Subscription s) {
        if (s.isUnsubscribed()) {
            return;
        }
        if (!this.unsubscribed) {
            synchronized (this) {
                if (!this.unsubscribed) {
                    List<Subscription> subs = this.subscriptions;
                    if (subs == null) {
                        subs = new LinkedList<Subscription>();
                        this.subscriptions = subs;
                    }
                    subs.add(s);
                    return;
                }
            }
        }
        s.unsubscribe();
    }
    
    public void remove(final Subscription s) {
        if (!this.unsubscribed) {
            final boolean unsubscribe;
            synchronized (this) {
                final List<Subscription> subs = this.subscriptions;
                if (this.unsubscribed || subs == null) {
                    return;
                }
                unsubscribe = subs.remove(s);
            }
            if (unsubscribe) {
                s.unsubscribe();
            }
        }
    }
    
    @Override
    public void unsubscribe() {
        if (!this.unsubscribed) {
            final List<Subscription> list;
            synchronized (this) {
                if (this.unsubscribed) {
                    return;
                }
                this.unsubscribed = true;
                list = this.subscriptions;
                this.subscriptions = null;
            }
            unsubscribeFromAll(list);
        }
    }
    
    private static void unsubscribeFromAll(final Collection<Subscription> subscriptions) {
        if (subscriptions == null) {
            return;
        }
        List<Throwable> es = null;
        for (final Subscription s : subscriptions) {
            try {
                s.unsubscribe();
            }
            catch (Throwable e) {
                if (es == null) {
                    es = new ArrayList<Throwable>();
                }
                es.add(e);
            }
        }
        JVMUtil.throwIfAny(es);
    }
    
    public void clear() {
        if (!this.unsubscribed) {
            final List<Subscription> list;
            synchronized (this) {
                list = this.subscriptions;
                this.subscriptions = null;
            }
            unsubscribeFromAll(list);
        }
    }
    
    public boolean hasSubscriptions() {
        if (!this.unsubscribed) {
            synchronized (this) {
                return !this.unsubscribed && this.subscriptions != null && !this.subscriptions.isEmpty();
            }
        }
        return false;
    }
}
